#include "StdAfx.h"

#include <PSDFCore/Network/NetworkCenter.h>
#include <PSDFCore/Data/DataCenter.h>

using namespace boost::asio;

NetworkCenter::NetworkCenter()
{
	_recognizer = new DefaultDataRecognizer;

	_multicast = NULL;
	_tcp = NULL;
	_udp = NULL;
}

NetworkCenter::~NetworkCenter()
{
	if (_recognizer) { delete _recognizer; }

	if (_multicast) { _multicast->quit(); }
	if (_tcp) { _tcp->quit(); }
	if (_udp) { _udp->quit(); }

	if (_multicast) 
	{
		PosixThread::waitUntilDone(_multicast->getThreadId());
		delete _multicast;
	}
	if (_tcp)
	{
		PosixThread::waitUntilDone(_tcp->getThreadId());
		delete _tcp;
	}
	if (_udp)
	{
		PosixThread::waitUntilDone(_udp->getThreadId());
		delete _udp;
	}
}

NetworkCenter* NetworkCenter::inst()
{
	static NetworkCenter instance;
	return &instance;
}

NetworkCenter::Multicast* NetworkCenter::multicast()
{
	if (_multicast == NULL) { _multicast = new Multicast; }
	return _multicast;
}

NetworkCenter::TCP* NetworkCenter::tcp()
{
	if (_tcp == NULL) { _tcp = new TCP; }
	return _tcp;
}

NetworkCenter::UDP* NetworkCenter::udp()
{
	if (_udp == NULL) { _udp = new UDP; }
	return _udp;
}

void NetworkCenter::setDataRecognizer(NetworkDataRecognizer* recognizer)
{
	if (recognizer == NULL) { return; }
	if (_recognizer) { delete _recognizer; }
	_recognizer = recognizer;
}

void NetworkCenter::onReceive( char* data, size_t length )
{
	int dataType = _recognizer->recognize(data, length);
	int dataIndex = DataCenter::inst()->addData(data, length);
	_recognizer->triggerDataEvent(dataType, dataIndex);
}



//-------------------------------------
// Multicast
//-------------------------------------
bool NetworkCenter::Multicast::joinGroup( const string ipAddr, unsigned short recvPort )
{
	ip::address listenAddress = ip::address::from_string("0.0.0.0"); // any address

	_recvPort = recvPort;
	ip::udp::endpoint listenEndpoint(listenAddress, recvPort);

	try
	{
		_socket.open(listenEndpoint.protocol());
		_socket.set_option(ip::udp::socket::reuse_address(true));
		_socket.bind(listenEndpoint);

		// join the multicast group
		_address = ip::address::from_string(ipAddr);
		_socket.set_option(ip::multicast::join_group(_address));

		this->start();

		return true;
	}
	catch(...)
	{
		return false;
	}
}

bool NetworkCenter::Multicast::send( char* data, size_t length )
{
	io_service ioService;
	ip::udp::endpoint ep(_address, _recvPort);
	ip::udp::socket sendSocket(ioService, ep.protocol());
	try
	{
		sendSocket.send_to(buffer(data, length), ep);
		return true;	
	}
	catch(...)
	{
		return false;
	}
}

void NetworkCenter::Multicast::run()
{
	while (true)
	{
		try
		{
			size_t size = _socket.receive(buffer(_buffer, BUFFER_MAXLENGTH));
			NetworkCenter::inst()->onReceive(_buffer, size);
		}
		catch(...)
		{
			return;
		}
	}
}

void NetworkCenter::Multicast::quit()
{
	try
	{
		_socket.shutdown(ip::udp::socket::shutdown_both);
	}
	catch(...) {}
	try
	{
		_socket.close();
	}
	catch(...) {}
	try
	{
		_ioService.stop();
	}
	catch(...) {}
}


//----------------------------------------
// TCP
//----------------------------------------
bool NetworkCenter::TCP::connect( const string ipAddr, unsigned short port )
{
	return true;
}

bool NetworkCenter::TCP::send( char* data, size_t length )
{
	return true;
}

void NetworkCenter::TCP::run()
{

}

void NetworkCenter::TCP::quit()
{

}


//------------------------------------
// UDP
//------------------------------------
bool NetworkCenter::UDP::connect( const string ipAddr, unsigned short port )
{
	return true;
}

bool NetworkCenter::UDP::send( char* data, size_t length )
{
	return true;
}

void NetworkCenter::UDP::run()
{

}

void NetworkCenter::UDP::quit()
{

}
